11. Exercise: Refactor onCreateViewHolder

L7 17 ViewHolders Refactor SC PART 2

Now it’s your turn to complete this exercise yourself.

In this exercise, we’ll continue the refactor we started in the prior lesson by encapsulating the logic for creating the ViewHolder into a method called from(), which we’ll then place into a companion object in the ViewHolder class.

  1. Encapsulate the logic for creating the ViewHolder.

    Select the code in onCreateViewHolder() and, using the same process as above, refactor it into a public method called from.

    Watch the video to see how to use Android Studio tools to do most of this refactor for you.


  2. Move the from code into a companion object.

    Click option-enter on the from method, and select Move to companion object. Then move the resulting companion object into the ViewHolder class.


  3. Change the ViewHolder class declaration to be a private constructor:

class ViewHolder private constructor(itemView: View)


  1. Finally, change the return statement in onBindViewHolder to return ViewHolder.from(parent).

    Your refactored SleepNightAdapter should now look like this:

     class SleepNightAdapter : RecyclerView.Adapter<SleepNightAdapter.ViewHolder>() {
    var data = listOf&lt;SleepNight&gt;()
        set(value) {
            field = value
            notifyDataSetChanged()
        }
    
    override fun getItemCount() = data.size
    
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val item = data[position]
    
        holder.bind(item)
    }
    
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return ViewHolder.from(parent)
    }
    
    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
        val sleepLength: TextView = itemView.findViewById(R.id.sleep_length)
        val quality: TextView = itemView.findViewById(R.id.quality_string)
        val qualityImage: ImageView = itemView.findViewById(R.id.quality_image)
    
        fun bind(item: SleepNight) {
            val res = itemView.context.resources
    
            sleepLength.text = convertDurationToFormatted(item.startTimeMilli, item.endTimeMilli, res)
            quality.text = convertNumericQualityToString(item.sleepQuality, res)
            qualityImage.setImageResource(when (item.sleepQuality) {
                0 -&gt; R.drawable.ic_sleep_0
                1 -&gt; R.drawable.ic_sleep_1
                2 -&gt; R.drawable.ic_sleep_2
                3 -&gt; R.drawable.ic_sleep_3
                4 -&gt; R.drawable.ic_sleep_4
                5 -&gt; R.drawable.ic_sleep_5
                else -&gt; R.drawable.ic_sleep_active
            })
        }
    
        companion object {
            fun from(parent: ViewGroup): ViewHolder {
                val layoutInflater = LayoutInflater.from(parent.context)
                val view = layoutInflater
               .inflate(R.layout.list_item_sleep_night, parent, false)
    
                return ViewHolder(view)
            }
         }
       }
    }


  2. Run the app and verify that it runs exactly as it did before the refactor.

Wow, that was a lot of steps! And the app didn’t change at all! But by using encapsulation to achieve separation of concerns, you’ve made your code much more readable, and easier to maintain.

If you want to start at this step, you can download this exercise from: Step.06-Exercise-Refactor-onCreateViewHolder.

You will find plenty of //TODO comments to help you complete this exercise, and if you get stuck, go back and watch the video again.

Once you’re done, you can check your solution against the solution we’ve provided here: Step.06-Solution-Refactor-onCreateViewHolder, or using this git diff.

Task Description:

Complete these steps to refactor onCreateViewHolder().

Task List:

Task Feedback:

Great job! Your encapsulated ViewHolder is so much simpler!